package cn.wisenergy.pai.monitor.linux.parser;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.StringTokenizer;

import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 
 * <p>
 * 取得linux系统下的主机名、IP、内存信息、cpu、磁盘读写速率、网络接受发送速率
 */
public final class LinuxSystemTool {

	static final Logger LOG = LoggerFactory.getLogger(LinuxSystemTool.class);

	/**
	 * get memary by used /proc/meminfo
	 * 
	 * @return float efficiency
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static long[] getMemInfo() {
		File file = new File("/proc/meminfo");
		long[] result = new long[] { 0l, 0l, 0l, 0l, 0l, 0l };
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(
					file)));
			String str = null;
			StringTokenizer token = null;
			while ((str = br.readLine()) != null) {
				token = new StringTokenizer(str);
				if (!token.hasMoreTokens())
					continue;
				str = token.nextToken();
				if (!token.hasMoreTokens())
					continue;
				if (str.equalsIgnoreCase("MemTotal:"))
					result[0] = Integer.parseInt(token.nextToken());
				else if (str.equalsIgnoreCase("MemFree:"))
					result[1] = Integer.parseInt(token.nextToken());
				else if (str.equalsIgnoreCase("SwapTotal:"))
					result[2] = Integer.parseInt(token.nextToken());
				else if (str.equalsIgnoreCase("SwapFree:"))
					result[3] = Integer.parseInt(token.nextToken());
				else if (str.equalsIgnoreCase("Buffers:"))
					result[4] = Integer.parseInt(token.nextToken());
				else if (str.equalsIgnoreCase("Cached:"))
					result[5] = Integer.parseInt(token.nextToken());
			}
		} catch (Exception e) {
			if (LOG.isDebugEnabled()) {
				LOG.debug("can't get memory info");
			}
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					LOG.warn("can't close /proc/meminfo");
				}
			}
		}
		return result;
	}

	/**
	 * get cpu by used /proc/stat
	 * 
	 * @return float efficiency
	 * @throws IOException
	 * @throws InterruptedException
	 */
	public static long[] getCpuInfo() {
		long[] in = new long[] { 0l, 0l, 0l, 0l,0l,0l,0l };
		File file = null;
		BufferedReader br = null;
		try {
			file = new File("/proc/stat");
			br = new BufferedReader(new InputStreamReader(new FileInputStream(
					file)));
			StringTokenizer token = new StringTokenizer(br.readLine());
			token.nextToken();
			long user1 = Long.parseLong(token.nextToken());
			long nice1 = Long.parseLong(token.nextToken());
			long sys1 = Long.parseLong(token.nextToken());
			long idle1 = Long.parseLong(token.nextToken());
			long iow=Long.parseLong(token.nextToken());
			long irq=Long.parseLong(token.nextToken());
			long sirq=Long.parseLong(token.nextToken());
			in[0] = user1;
			in[1] = nice1;
			in[2] = sys1;
			in[3] = idle1;
			in[4] = iow;
			in[5] = irq;
			in[6] = sirq;
		} catch (Exception e) {
			if (LOG.isDebugEnabled()) {
				LOG.debug("can't get cpu info");
			}
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					LOG.warn("can't close the /proc/stat reader");
				}
			}
		}
		return in;
	}
	public static CPU calculateCPU(long[] in1,long[] in2){
		float usedcpu = 0f;
		float use=0f;
		float sys=0f;
		float iow=0f;
		float nic=0f;
		float idl=0f;
		float irq=0f;
		float sirq=0f;
		float tt2=(float)(in2[0] + in2[1] + in2[2] + in2[3]+in2[4]+in2[5]+in2[6]);
		float tt1=(float)(in1[0]+ in1[1] + in1[2] + in1[3]+in1[4]+in1[5]+in1[6]);
		usedcpu = ((in2[0] + in2[2] + in2[1]) - (in1[0] + in1[2] + in1[1]))/(tt2-tt1);
		use= (in2[0]-in1[0])/(tt2-tt1);
		nic=  (in2[1]-in1[1])/(tt2-tt1);
		sys=  (in2[2]-in1[2])/(tt2-tt1);
		idl=  (in2[3]-in1[3])/(tt2-tt1);
		iow=  (in2[4]-in1[4])/(tt2-tt1);
		irq=  (in2[5]-in1[5])/(tt2-tt1);
		sirq=  (in2[6]-in1[6])/(tt2-tt1);
		CPU cpu = new CPU();
		cpu.setCpu(usedcpu);
		cpu.setIdl(idl);
		cpu.setIow(iow);
		cpu.setIrq(irq);
		cpu.setNic(nic);
		cpu.setSirq(sirq);
		cpu.setSys(sys);
		cpu.setUse(use);
		return cpu;
	}
	public static TimeNode getCurrentTimeNode() throws InterruptedException {
		TimeNode currentTimeNode = new TimeNode();
		Time time = new Time();
		time.setTime(System.currentTimeMillis());
		currentTimeNode.setTime(time);
		HostSpot hostspot = HostSpot.getCurrentHostSpot();
		currentTimeNode.setHostspot(hostspot);
		
		long[] in1 = getCpuInfo();
		long[] net1 = getNetInfo();
		long[] disk1 = getDiskInfo();
		Thread.sleep(5000);
		long[] in2 = getCpuInfo();
		long[] net2 = getNetInfo();
		long[] disk2 = getDiskInfo();
		long netreceive = 0;
		long netsend = 0;
		float diskread = 0;
		float diskwrite = 0;
		netreceive = (net2[0] - net1[0]) / 1024;
		netsend = (net2[1] - net1[1]) / 1024;

		diskread = (disk2[0] - disk1[0]) / 1024;
		diskwrite = (disk2[1] - disk1[1]) / 1024;
		//cpu
		currentTimeNode.setCpu(calculateCPU(in1,in2));
		//memory
		long[] memInfo = LinuxSystemTool.getMemInfo();
		Memory mem = new Memory();
		mem.setTotalMem(memInfo[0]);
		mem.setFreeMem(memInfo[1]);
		mem.setSwapFree(memInfo[3]);
		mem.setSwapTotal(memInfo[2]);
		long avalible=memInfo[1] + memInfo[4] + memInfo[5];
		mem.setAvaliableMem(avalible);
		float used=(memInfo[0]-avalible)/(float)memInfo[0];
		mem.setUsedMem(used);
		currentTimeNode.setMem(mem);
		//disk
		Disk disk = new Disk();
		disk.setDiskread(diskread);
		disk.setDiskwrite(diskwrite);
		currentTimeNode.setDisk(disk);
		//network
		NetWork nets = new NetWork();
		nets.setNetaccept(netreceive);
		nets.setNetsend(netsend);
		currentTimeNode.setNets(nets);
		
		return currentTimeNode;
	}

	/**
	 * get disk by used /proc/diskstats
	 * 
	 * @return float efficiency
	 * @throws IOException
	 * @throws InterruptedException
	 */
	private static long[] getDiskInfo() {
		long[] disk1 = new long[] { 0l, 0l };

		try {
			List<String> list1 = new ArrayList<String>();
			File file1 = new File("/proc/diskstats");
			list1 = FileUtils.readLines(file1);
			String[] ds = null;
			for (int i = 0; i < list1.size(); i++) {
				String line = list1.get(i).trim();
				if (line.contains("sda")) {
					ds = line.split("\\s+");
					disk1[0] = Long.parseLong(ds[5]);
					disk1[1] = Long.parseLong(ds[9]);
					break;
				}
			}
		} catch (IOException e) {
			if (LOG.isDebugEnabled())
				LOG.debug("can't get diskstats");
		}

		return disk1;
	}

	/**
	 * get net by used /proc/net/dev
	 * 
	 * @return long efficiency
	 */
	private static long[] getNetInfo() {
		long[] net1 = new long[] { 0l, 0l };
		try {
			String[] ds = null;
			String tmp1 = "0";
			long receive1 = 0l, transmit1 = 0l;

			List<String> list1 = new ArrayList<String>();
			File file1 = new File("/proc/net/dev");
			list1 = FileUtils.readLines(file1);
			for (int i = 0; i < list1.size(); i++) {
				String line = list1.get(i);
				line = line.trim();
				if (line.startsWith("eth0")) {
					ds = line.split("\\s+");
					break;
				}
			}
			receive1 = Long.parseLong(ds[1]);
			transmit1 = Long.parseLong(ds[9]);
			net1[0] = receive1;
			net1[1] = transmit1;
		} catch (Exception e) {
			if (LOG.isDebugEnabled()) {
				LOG.debug("can't get network recive data");
			}
		}

		return net1;
	}
}